home *** CD-ROM | disk | FTP | other *** search
/ AppleScript - The Beta Release / AppleScript - The Beta Release.iso / Documentation / develop / Better Apple Event Coding / Code Samples / UMAFailure.p < prev   
Encoding:
Text File  |  1992-10-16  |  8.7 KB  |  219 lines  |  [TEXT/MPS ]

  1. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  2. { UFailure.p }
  3. { Copyright © 1985-1990 by Apple Computer, Inc.  All rights reserved. }
  4.  
  5. {[f-]}
  6. (*
  7.                 T H E O R Y  O F     O P E R A T I O N
  8.  
  9.     This unit implements the MacApp failure mechanism.
  10.  
  11.     The failure mechanism is built around exception handlers.    An exception
  12.     handler is a routine, generally local to some other routine, that is
  13.     called when a failure occurs and takes action to handle the failure.
  14.     An exception handler is of the form
  15.  
  16.     PROCEDURE ExceptionHandler (error: OSErr; message: LONGINT);
  17.  
  18.     where error is the error that caused the failure, and message identifies
  19.     the error message that may be displayed.  Consider a routine that opens
  20.     a file, reads its contents, and closes the file.  If a failure occured
  21.     while reading the file, an exception handler would be needed to close the
  22.     file, as the rest of the routine will not be executed.    (See the example
  23.     at the end of these comments.)
  24.  
  25.     References to expection handlers are defined by the FailInfo record.
  26.     The exception handlers form a linked-list via the nextInfo field of
  27.     FailInfo.    The linked list is a stack since new exception handlers
  28.     are added to the front of the list.
  29.  
  30.     New exception handlers are added to the stack with the CatchFailures
  31.     procedure, and removed from the stack with the Success procedure.    In
  32.     general you call CatchFailures to post an exception handler when an
  33.     error the application should handle might occur, and call Success to
  34.     remove the handler from the stack, after the handler is no longer
  35.     needed (i.e. the possibility of error no longer exists).  Any failure
  36.     detected within the limits of the CatchFailures and subsequent Success
  37.     call results in the execution of the exception handler.  (Failure does
  38.     not have to occur in the same routine as your call to CatchFailures.
  39.     The failure may occur in any routine called after CatchFailures but
  40.     before Success.)
  41.  
  42.     When MacApp (or your code) determines that a failure has occured, it
  43.     calls Failure.    As a convenience, several procedures are provided
  44.     to check for standard kinds of failures and call Failure if needed.
  45.     These procedures are:
  46.  
  47.     FailNIL         Calls Failure if its parameter is NIL.
  48.     FailOSErr        Calls Failure if its parameter is not noErr.
  49.     FailMemError    Calls Failure if MemError returns other than noErr.
  50.     FailResError    Calls Failure if ResError returns other than noErr.
  51.  
  52.     When Failure is called, execution of the routine that called Failure is
  53.     terminated and the exception handler at the top of the stack is popped.
  54.     For each routine that was called after the handler was posted
  55.     to the stack, execution is terminated as though from an EXIT statement.
  56.     Then the exception handler is called.    It generally cleans up for the
  57.     routine in which it is nested.    Upon completion the next exception handler
  58.     is popped from the stack, repeating the process.
  59.  
  60.     The error causing the failure, and a message code is passed to Failure.
  61.     For MacApp, the last exception handler on the stack is the one in
  62.     TApplication.PollEvent.  It calls TApplication.ShowError, which calls
  63.     ErrorAlert, which decodes the message and displays an alert.  You exception
  64.     handlers may set the message code to one more specific to your application
  65.     by calling FailNewMessage at the end of your exception handler.
  66.     FailNewMessage changes the message only if the current one is non-zero.
  67.     This has the effect of allowing those exception handlers closest to the
  68.     source of the error to set the message.
  69.  
  70.     One last note about exception handlers:  It is possible for an exception
  71.     handler to terminate exception processing by using a non-local GOTO to
  72.     jump back into the routine in which the exception handler is nested.  This
  73.     is how MacApp keeps the application running when a failure occurs.    The
  74.     last exception handler on the stack, in TApplication.PollEvent, uses a
  75.     GOTO to continue event processing.
  76.  
  77.     The following is an example showing the use of exception handlers.
  78.     The ReadTheFile procedure reads the contents of a file, signalling
  79.     failure if the open, read, or close returns an error.
  80.  
  81.     PROCEDURE ReadTheFile (fileName: Str255; volRefNum: INTEGER;
  82.                             VAR contents: ContentsRecord);
  83.     VAR
  84.         fi:         FailInfo;
  85.         count:        LONGINT;
  86.  
  87.         PROCEDURE ExceptionHandler (error: OSErr; message: LONGINT);
  88.         VAR
  89.             err:    OSErr;
  90.         BEGIN
  91.             err := FSClose(fileRefNum);     { Make sure the file is closed }
  92.             { Pass on my own error message... }
  93.             FailNewMessage(error, message, kMyErrorMessage);
  94.         END;
  95.  
  96.     BEGIN
  97.         { If FSOpen fails we don't need to do any failure handling,
  98.             though the guy that called us probably will. }
  99.         FailOSErr(FSOpen(fileName, volRefNum, fileRefNum));
  100.  
  101.         { Now that the file is open, if the read fails we must make
  102.             sure to close the file. }
  103.         CatchFailures(fi, Exceptionhandler);
  104.  
  105.         count := SIZEOF(ContentsRecord);
  106.         FailOSErr(FSRead(fileRefNum, count, @contents));
  107.  
  108.         { The file's been read so we don't need our exception handler
  109.             anymore. }
  110.         Success(fi);
  111.  
  112.         { Again, the guy that called us will have to deal with this. }
  113.         FailOSErr(FSClose(fileRefNum));
  114.     END;
  115. *)
  116. {[f+]}
  117.  
  118. UNIT UFailure;
  119.  
  120.     INTERFACE
  121.  
  122.         USES Types, Memory, Resources, Errors;
  123.  
  124.         CONST
  125.             minErr                = - 32768;                { Low error number }
  126.             maxErr                = 32767;                { High error number }
  127.  
  128.         TYPE
  129.             { used for the exception handling mechanism }
  130.             FailInfoPtr         = ^FailInfo;            { Preferred. The pointer
  131.                                                         type _MUST_ be declared first since the record
  132.                                                         is self referential }
  133.             FailInfo            = RECORD
  134.                 regs:                ARRAY [1..11] OF LONGINT; { The saved registers as of the
  135.                                                                CatchFailures. }
  136.                 error:                INTEGER;            { The error condition passed to Failure. }
  137.                 message:            LONGINT;            { The message which accompanied the Failure.
  138.                                                          }
  139.                 failA6:             LONGINT;            { A6 of the caller to CatchFailures. }
  140.                 failPC:             LONGINT;            { Address of failure handler routine. }
  141.                 nextInfo:            FailInfoPtr;        { Next in stack. }
  142.                 END;
  143.             PFailInfo            = FailInfoPtr;            { Left in for compatibility (2.0) }
  144.  
  145.         VAR
  146.             {$Push} {$J+}                                { Defined externally }
  147.             gTopHandler:        FailInfoPtr;            { Most recent link in linked list of failure
  148.                                                          handlers. Set to nil by a constant in
  149.                                                          UFailure.a so that Failure handling never
  150.                                                          needs to be initialized. }
  151.             {$Pop}
  152.  
  153.         PROCEDURE Assertion(condition: BOOLEAN;
  154.                             description: StringPtr);
  155.         { Asserts a condition.If condition is FALSE : IF debugging : prints description and stops in
  156.         Debugger ELSE : Signals a general failure. }
  157.  
  158.         FUNCTION BuildMessage(lowWord, highWord: INTEGER): LONGINT;
  159.             INLINE $2E9F;                                { MOVE.L (A7)+,(A7) }
  160.         { Takes the 2 integers and combines them into a LONGINT failure message.  Note that the
  161.         low-order word is the first parameter. }
  162.  
  163.         PROCEDURE CatchFailures(VAR fi: FailInfo;
  164.                                 PROCEDURE Handler(e: INTEGER;
  165.                                                   m: LONGINT));
  166.         { Call this to set up an exception handler. This pushes your handler onto
  167.         a stack of exception handlers. }
  168.  
  169.         PROCEDURE EachFailureHandlerDo(PROCEDURE DoToHandler(fiPtr: FailInfoPtr));
  170.         { Calls DoToHandler for each failure handler in the stack from gTopHandler
  171.         to the outermost handler. }
  172.  
  173.         PROCEDURE Failure(error: INTEGER;
  174.                           message: LONGINT);
  175.         { Call this to signal a failure.  Control will branch to the most recent
  176.         exception handler, which will be popped off the handler stack. }
  177.  
  178.         PROCEDURE FailMemError;
  179.         { IF MemError <> noErr THEN Failure(MemError, 0); If you are using
  180.         assembler, then you should just test the return code from the Memory
  181.         Manager in DO by calling FailOSErr. (See the discussion of MemError in
  182.         Inside Macintosh.) }
  183.  
  184.         PROCEDURE FailResError;
  185.         { IF ResError <> noErr THEN Failure(ResError, 0); (See Inside Macintosh.) }
  186.  
  187.         PROCEDURE FailNewMessage(error: INTEGER;
  188.                                  oldMessage, newMessage: LONGINT);
  189.         { This does:
  190.         IF oldMessage = 0 THEN
  191.             Failure(error, newMessage)
  192.         ELSE
  193.             Failure(error, oldMessage);
  194.         }
  195.  
  196.         PROCEDURE FailNIL(p: UNIV Ptr);
  197.         { Call this with a pointer/handle; this signals Failure(memFullErr, 0) if p is NIL. }
  198.  
  199.         PROCEDURE FailNILResource(r: UNIV Handle);
  200.         { Call this with a resource handle; this signals Failure if the handle is nil. The error is
  201.         either that returned by ResError, or resNotFound if ResError returns no error. }
  202.  
  203.         PROCEDURE FailOSErr(error: INTEGER);
  204.         { Call this with an OSError; signals Failure(error, 0) if error <> noErr. }
  205.  
  206.         FUNCTION HandlerExists(testFailInfoPtr: FailInfoPtr): BOOLEAN;
  207.         { This test returns TRUE if the failure handler exists in the stack from gTopHandler
  208.         to the outermost handler.  }
  209.  
  210.         PROCEDURE Success(VAR fi: FailInfo);
  211.         { Call this when you want to pop your exception handler. We assume that the programmer passes
  212.         in the most recent FailInfo record; ie. the one that is the top of the stack. If debugging
  213.         is on, we check to be sure. }
  214.  
  215. IMPLEMENTATION
  216.  
  217.     {$I UMAFailure.inc1.p}
  218. END.
  219.